package eu.davidea.samples.flexibleadapter;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.ViewGroup;

import java.util.List;

import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.utils.Utils;
import eu.davidea.samples.flexibleadapter.items.ScrollableExpandableItem;
import eu.davidea.samples.flexibleadapter.items.ScrollableFooterItem;
import eu.davidea.samples.flexibleadapter.items.ScrollableLayoutItem;
import eu.davidea.samples.flexibleadapter.items.ScrollableSubItem;
import eu.davidea.samples.flexibleadapter.items.ScrollableULSItem;
import eu.davidea.samples.flexibleadapter.services.DatabaseConfiguration;

/**
 * This is a custom implementation extending FlexibleAdapter. {@code AbstractFlexibleItem} is
 * used as most common Item for ALL view types.
 * <p>Items are bound with <b>METHOD A</b> (new way): AutoMap is active, you <u>don't have to</u>
 * implement {@code getItemViewType, onCreateViewHolder, onBindViewHolder}.</p>
 * Check {@code OverallAdapter} for <b>METHOD B</b> (classic way).
 *
 * @see OverallAdapter
 * @see AbstractFlexibleItem
 */
public class ExampleAdapter extends FlexibleAdapter<AbstractFlexibleItem> {

    private static final String TAG = ExampleAdapter.class.getSimpleName();

    private Context mContext;

    public ExampleAdapter(List<AbstractFlexibleItem> items, Object listeners) {
        //stableIds ? true = Items implement hashCode() so they can have stableIds!
        //这个方法返回true是实现了hashCode(),这个可以保证每个item的唯一性（稳定性）
        super(items, listeners, true);

        //In case you need a Handler, do this:
        //- Overrides the internal Handler with a custom callback that extends the internal one
        //这里需要定义一个Handler，它是重写了内部与自定义了回调处理，这样可以扩展内部
        mHandler = new Handler(Looper.getMainLooper(), new MyHandlerCallback());
    }

    @Override
    public void updateDataSet(List<AbstractFlexibleItem> items, boolean animate) {
        // NOTE: To have views/items not changed, set them into "items" before passing the final
        // list to the Adapter.l

        // Overwrite the list and fully notify the change, pass false to not animate changes.
        // Watch out! The original list must a copy.
        super.updateDataSet(items, animate);

        // onPostUpdate() will automatically be called at the end of the Asynchronous update
        // process. Manipulate the list inside that method only or you won't see the changes.
        //这个方onPostUpdate()将自动调用异步更新过程，在列表里面操作，或者当你看不到的时候改变
    }

    /*l
     * You can override this method to define your own concept of "Empty".
     * This method is never called internally.
     * 你可以重写这个方法来定义你自己的空视图，这个方法没有在内部被调用
     */
    @Override
    public boolean isEmpty() {
        return super.isEmpty();
    }

    /*
     * HEADER VIEW
     * This method shows how to add Header View as it was for ListView.
     * Same Header item is enqueued for removal with a delay.
     * The view is represented by a custom Item type to better represent any dynamic content.
     * 标题视图
     * 这个方法显示了如何添加视图和列表视图
     * 相同标题项排列入队的时候会清除延迟
     * 这个视图锁代表的是一个定制的项目类型，可以更好的代表任何动态内容。
     */
    public void showLayoutInfo(boolean scrollToPosition) {
        if (!hasSearchText()) {
            final ScrollableLayoutItem item = new ScrollableLayoutItem("LAY-L");
            if (mRecyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
                item.setId("LAY-S");
                item.setTitle(mRecyclerView.getContext().getString(R.string.staggered_layout));
            } else if (mRecyclerView.getLayoutManager() instanceof GridLayoutManager) {
                item.setId("LAY-G");
                item.setTitle(mRecyclerView.getContext().getString(R.string.grid_layout));
            } else {
                item.setTitle(mRecyclerView.getContext().getString(R.string.linear_layout));
            }
            item.setSubtitle(mRecyclerView.getContext().getString(
                    R.string.columns,
                    String.valueOf(Utils.getSpanCount(mRecyclerView.getLayoutManager())))
            );
            // NOTE: If you have to change at runtime the LayoutManager AND add
            // Scrollable Headers, consider to add them in post, using a delay >= 0
            // otherwise scroll animations on all items will not start correctly.
            //如果你必须在运行时改变LayoutManager和添加滚动的头，应该考虑在添加后，使用延迟>=0，否则滚动动画无法正常启动
            addScrollableHeaderWithDelay(item, 1200L, scrollToPosition);
            removeScrollableHeaderWithDelay(item, 4000L);
        }
    }

    /*
     * ANOTHER HEADER VIEW
     * This method showcases how to add a Header View with a delay.
     * The view is represented by a custom Item type to better represent any dynamic content.
     * 另一个视图标题
     * 此方法展示了如何添加一个标题视图与延迟
     * 为代表的观点是一个定制的项目类型，以更好地代表任何动态内容
     */
    public void addUserLearnedSelection(boolean scrollToPosition) {
        if (!DatabaseConfiguration.userLearnedSelection && !hasSearchText() && !(getItem(0)
                instanceof ScrollableULSItem)) {
            final ScrollableULSItem item = new ScrollableULSItem("ULS");
            item.setTitle(mRecyclerView.getContext().getString(R.string.uls_title));
            item.setSubtitle(mRecyclerView.getContext().getString(R.string.uls_subtitle));
            addScrollableHeaderWithDelay(item, 1000L, false);
        }
    }

    /*
     * FOOTER VIEW
     * This method showcases how to delay add a Footer View.
     * The view is represented by a custom Item type to better represent any dynamic content.
     * 脚页视图
     * 这个方法实现了如何延迟脚页视图的加载
     * 这个视图代表了自定义类型的Item用来更好的去表示任何的动态内容
     * 这是一个可滚动的View
     */
    public void addScrollableFooter() {
        final ScrollableFooterItem item = new ScrollableFooterItem("SFI");
        item.setTitle(mRecyclerView.getContext().getString(R.string.scrollable_footer_title));
        item.setSubtitle(mRecyclerView.getContext().getString(R.string.scrollable_footer_subtitle));
        addScrollableFooterWithDelay(item, 1000L, false);
    }

    /*
     * Showcase for EXPANDABLE HEADER VIEW
     * 为扩展标题视图展示
     */
    public void addScrollableExpandableAsHeader() {
        final ScrollableExpandableItem expandable = new ScrollableExpandableItem("SEHI");
        expandable.setTitle(mRecyclerView.getContext().getString(R.string
                .scrollable_expandable_header_title));
        expandable.setSubtitle(mRecyclerView.getContext().getString(R.string
                .scrollable_expandable_header_subtitle));
        expandable.addSubItem(new ScrollableSubItem("SEHI_1"));
        expandable.addSubItem(new ScrollableSubItem("SEHI_2"));
        addScrollableHeaderWithDelay(expandable, 1500L, false);
    }

    /*
     * Showcase for EXPANDABLE FOOTER VIEW
     */
    public void addScrollableExpandableAsFooter() {
        final ScrollableExpandableItem expandable = new ScrollableExpandableItem("SEFI");
        expandable.setTitle(mRecyclerView.getContext().getString(R.string
                .scrollable_expandable_footer_title));
        expandable.setSubtitle(mRecyclerView.getContext().getString(R.string
                .scrollable_expandable_footer_subtitle));
        expandable.addSubItem(new ScrollableSubItem("SEFI_1"));
        expandable.addSubItem(new ScrollableSubItem("SEFI_2"));
        addScrollableFooterWithDelay(expandable, 1500L, false);
    }

    /**
     * This is a customization of the Layout that hosts the header when sticky.
     * The code works, but it is commented because not used (default is used).
     * <p><b>Note:</b> You now can set a custom container by calling
     * {@link #setStickyHeaderContainer(ViewGroup)}</p>
     */
//	@Override
//	public ViewGroup getStickyHeaderContainer() {
//		FrameLayout frameLayout = new FrameLayout(mRecyclerView.getContext());
//		frameLayout.setLayoutParams(new ViewGroup.LayoutParams(
//				ViewGroup.LayoutParams.WRAP_CONTENT, //or MATCH_PARENT
//				ViewGroup.LayoutParams.WRAP_CONTENT));
//		((ViewGroup) mRecyclerView.getParent()).addView(frameLayout); //This is important
// otherwise the Header disappears!
//		return (ViewGroup) mInflater.inflate(R.layout.sticky_header_layout, frameLayout);
//	}

    /**
     * METHOD A - NEW! Via Model objects. In this case you don't need to implement this method!
     * METHOD B - You override and implement this method as you prefer (don't call super).
     */
//	@Override
//	public int getItemViewType(int position) {
//		//Not implemented: METHOD A is used
//	}

    /**
     * METHOD A - NEW! Via Model objects. In this case you don't need to implement this method!
     * METHOD B - You override and implement this method as you prefer (don't call super).
     */
//	@Override
//	public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//		// Not implemented: METHOD A is used
//	}

    /**
     * METHOD A - NEW! Via Model objects. In this case you don't need to implement this method!
     * METHOD B - You override and implement this method as you prefer (don't call super).
     */
//	@Override
//	public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//		// Not implemented: METHOD A is used
//	}
    @Override
    public String onCreateBubbleText(int position) {
        if (position < getScrollableHeaders().size()) {
            return "Top";
        } else if (position >= getItemCount() - getScrollableFooters().size()) {
            return "Bottom";
        } else {
            position -= getScrollableHeaders().size() + 1;
        }
        // TODO FOR YOU: The basic value, usually, is the first letter
        // For me is the position
        return super.onCreateBubbleText(position);
    }

    /**
     * <b>IMPORTANT:</b> In order to preserve the internal calls, this custom Callback
     * <u>must</u> extends {@link FlexibleAdapter.HandlerCallback}
     * which implements {@link android.os.Handler.Callback},
     * therefore you <u>must</u> call {@code super().handleMessage(message)}.
     * <p>This handler can launch asynchronous tasks.</p>
     * If you catch the reserved "what", keep in mind that this code should be executed
     * <u>before</u> that task has been completed.
     * <p><b>Note:</b> numbers 0-9 are reserved for the Adapter, use others for new values.</p>
     * <p>
     * 在这里自定义一些任务，当完成后会自动回调这个方法去处理
     */
    private class MyHandlerCallback extends HandlerCallback {
        @Override
        public boolean handleMessage(Message message) {
            boolean done = super.handleMessage(message);
            switch (message.what) {
                // Currently reserved (you don't need to check these numbers!)
                case 0: //async updateDataSet
                case 1: //async filterItems
                case 2: //confirm delete
                case 8: //onLoadMore remove progress item
                    return done;
                // Free to use, example:
                case 10:
                case 11:
                    return true;
            }
            return false;
        }
    }

}